package org.to_zero.ssm.sdm.util;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @Author to_zero
 * @Description //Redis缓存
 * @Date 9:01 2020/10/26
 */
public class RedisUtil<T> {
    private static JedisPool pool;
    //param clazz 运行时类，通过类名和属性名拼接key
    private Class clazz;

    /**
     * 不传递calzz参数时，仅能够使用set、getString及del方法
     */
    public RedisUtil() {
        loadingConnectionPool();
    }


    public RedisUtil(Class<?> clazz) {
        this.clazz = clazz;
        loadingConnectionPool();
    }

    /**
     * 加载连接池
     */
    private static void loadingConnectionPool() {
        if (pool == null) {
            ResourceBundle bundle = ResourceBundle.getBundle("redis/redis");
            String host = bundle.getString("host");
            int port = Integer.parseInt(bundle.getString("port"));
            String password = bundle.getString("password");
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            jedisPoolConfig.setMaxTotal(Integer.parseInt(bundle.getString("maxTotal")));
            jedisPoolConfig.setMaxIdle(Integer.parseInt(bundle.getString("maxIdle")));
            jedisPoolConfig.setMaxWaitMillis(Long.parseLong(bundle.getString("maxWaitMillis")));
            if (Toolkit.isNull(password)) {
                pool = new JedisPool(jedisPoolConfig, host, port, 100000);
            } else {
                pool = new JedisPool(jedisPoolConfig, host, port, 100000, password);
            }
        }
    }

    private Jedis getJedis() {
        return pool.getResource();
    }

    private void close(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }

    /**
     * 存储数据至Redis缓存
     *
     * @param list 数据集合
     */
    public void storage(List<T> list) {
        Jedis jedis = getJedis();
        Field[] fields = clazz.getDeclaredFields();
        String className = clazz.getSimpleName();
        try {
            for (T t : list) {
                for (Field field : fields) {
                    String key = className.concat("_").concat(field.getName());
                    field.setAccessible(true);
                    Object obj = field.get(t);
                    if (Objects.nonNull(obj)) {
                        jedis.rpush(key, Toolkit.fieldTypeToString(obj));
                    }
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
    }

    /**
     * 取出Redis缓存数据
     *
     * @return 数据集
     */
    public List<T> takeOut() {
        Jedis jedis = getJedis();
        List<T> result = new ArrayList<>();
        String className = clazz.getSimpleName();
        Field[] fields = clazz.getDeclaredFields();
        String firstKey = jedis.keys(className.concat("_*")).iterator().next();
        int len = Math.toIntExact(jedis.llen(firstKey));
        try {
            for (int i = 0; i < len; i++) {
                T obj = (T) clazz.newInstance();
                for (Field field : fields) {
                    String key = className.concat("_").concat(field.getName());
                    if (jedis.exists(key)) {
                        String value = jedis.lindex(key, i);
                        String type = field.getType().getSimpleName();
                        Object val = Toolkit.stringToFieldType(value, type);
                        field.setAccessible(true);
                        field.set(obj, val);
                    }
                }
                result.add(obj);
            }
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return result;
    }

    /**
     * 清空相关缓存
     */
    public void clear() {
        Jedis jedis = getJedis();
        String prefix = clazz.getSimpleName().concat("_*");
        Set<String> keys = jedis.keys(prefix);
        if (!keys.isEmpty()) {
            String[] keysArray = keys.toArray(new String[keys.size()]);
            jedis.del(keysArray);
        }
        close(jedis);
    }

    /**
     * 判断是否存在相应的数据
     *
     * @param
     * @return
     */
    public boolean isEmptyByClass() {
        Jedis jedis = getJedis();
        Set<String> keys = jedis.keys(clazz.getSimpleName().concat("*"));
        close(jedis);
        return keys.isEmpty();
    }

    /**
     * 存储实体对象
     *
     * @param key
     * @param value
     */
    public void put(String key, Object value) {
        Jedis jedis = getJedis();
        Class clazz = value.getClass();
        Field[] fields = clazz.getDeclaredFields();
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                Object fieldVal = field.get(value);
                if (Toolkit.nonNull(fieldVal)) {
                    jedis.hset(key, field.getName(), Toolkit.fieldTypeToString(fieldVal));
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        jedis.expire(key, 60 * 60 * 24);
    }

    /**
     * 获取实体对象
     *
     * @param key
     * @return
     */
    public T get(String key) {
        Jedis jedis = getJedis();
        T obj = null;
        try {
            if (jedis.exists(key)) {
                obj = (T) clazz.newInstance();
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);
                    String fieldName = field.getName();
                    String type = field.getType().getSimpleName();
                    if (jedis.hexists(key, fieldName)) {
                        Object value = jedis.hget(key, fieldName);
                        field.set(obj, Toolkit.stringToFieldType(value, type));
                    }
                }
            }
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return obj;
    }

    public void set(String key, String value) {
        Jedis jedis = getJedis();
        if (Toolkit.nonNull(key)) {
            jedis.set(key, value);
        }
        close(jedis);
    }

    public String getString(String key) {
        Jedis jedis = getJedis();
        String value = jedis.exists(key) ? jedis.get(key) : "";
        close(jedis);
        return value;
    }

    public void del(String key) {
        Jedis jedis = getJedis();
        if (jedis.exists(key)) {
            jedis.del(key);
        }
        close(jedis);
    }
}
